

from typing import List, Type, Union

from emi.bar.storage.model import BaseDBModel
from emi.core.DBSource import DBSource, PeeweeModelSource
from emi.report.data import LogLevel, LogData
from emi.util import SqliteUtil
import peewee
from datetime import datetime, date


class LogDataModel(BaseDBModel):
    tag: str = peewee.TextField(index=True)
    level:int = peewee.SmallIntegerField(index=True)
    day_token:int = peewee.IntegerField(index=True)

    time:datetime = peewee.TimestampField(null=False)
    msg: str = peewee.TextField(null=False)
    exception_info:str = peewee.TextField(null=True)


    @staticmethod
    def from_data(data: LogData):
        db_bar = LogDataModel()
        db_bar.tag = data.tag
        db_bar.msg = data.msg
        db_bar.level = data.level.value
        db_bar.day_token = data.time.date().toordinal()
        db_bar.time = data.time
        db_bar.exception_info = data.exception_info
        return db_bar

    def to_bar(self,):
        data = LogData(
            level=LogLevel(self.level),
            time = self.time,
            msg=self.msg,
            tag=self.tag,
            exception_info=self.exception_info
        )
        return data


class LogDataDB:

    def __init__(self,source:DBSource,table_name = None):
        if table_name is None:
            table_name = 'log_data'
        self.source = source.init_peewee(table_name,LogDataModel,indexes=None,ignore_inited=True)

    def get_day_list(self)->List[date]:
        with self.source.use_peewee() as db_model:
            s = (db_model.select(db_model.day_token).order_by(db_model.day_token.asc()).distinct())
            return [date.fromordinal(model.day_token) for model in s]

    def get_tag_list(self) -> List[str]:
        """
        返回所有的symbol列表
        """
        with self.source.use_peewee() as db_model:
            s = (db_model.select(db_model.tag).distinct())
            return [v.tag for v in s]

    def get_newest_logs(self, count = 100,day:date = None,tags:List[str] = None,level:LogLevel = None) -> List[LogData]:
        """
        获取最新日报
        """
        with self.source.use_peewee() as db_model:
            conditions = []
            if day is not None:
                conditions.append(db_model.day_token == day.toordinal())
            if tags:
                conditions.append(db_model.tag.in_(tags))
            if level is not None:
                conditions.append(db_model.level == level.value)
            if conditions:
                s = (
                    db_model.select()
                    .where(*conditions).order_by(db_model.time.desc())
                        .limit(count)
                )
            else:
                s = (
                    db_model.select().order_by(db_model.time.desc())
                    .limit(count)
                )
            data = [db_bar.to_bar() for db_bar in s]
            return data


    def save_bars(self,datas:Union[LogData,List[LogData]]):
        """
        保存Bar数据。
        """
        if isinstance(datas,LogData):
            datas = [datas]
        ds = [LogDataModel.from_data(i) for i in datas]
        with self.source.use_peewee() as db_model:
            db_model.save_all(ds)

    def size(self, tag: str = None,day:date = None,level:LogLevel = None) -> int:
        with self.source.use_peewee() as db_model:
            conditions = []
            if day is not None:
                conditions.append(db_model.day_token == day.toordinal())
            if tag is not None:
                conditions.append(db_model.tag == tag)
            if level is not None:
                conditions.append(db_model.level == level.value)

            if not conditions:
                return db_model.select().count()
            else:
                return db_model.select().where(*conditions).count()

    def clear(self, tag: str = None,level:LogLevel = None):
        with self.source.use_peewee() as db_model:
            conditions = []
            if tag is not None:
                conditions.append(db_model.tag == tag)
            if level is not None:
                conditions.append(db_model.level == level.value)
            if conditions:
                db_model.delete().where(*conditions).execute()
            else:
                ##情况表
                db_model.drop_table()
                db_model.create_table()

    def clear_before(self, day: date, tag: str = None,level:LogLevel = None):
        with self.source.use_peewee() as db_model:
            conditions = [db_model.day_token <= day.toordinal()]
            if tag is not None:
                conditions.append(db_model.tag == tag)
            if level is not None:
                conditions.append(db_model.level == level.value)
            db_model.delete().where( *conditions).execute()